/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - core/containers
// Copyright( c) 2014.  All Rights Reserved
//
// File:		AEStringMap.h
// Author:		Gianluca Belardelli
// Date:		16/10/2014
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AESTRINGMAP_H_
#define _AESTRINGMAP_H_

struct AE_COREDLLIMPEXP AEStringMapOperations
{
	AE_FORCEINLINE static AEBOOL32 Equal( AEINT32 nKey0, AEINT32 nKey1 )
	{
		return strcmp( (const char*)nKey0, (const char*)nKey1 ) == 0;
	}

	AE_FORCEINLINE static AEUINT32 Hash( AEINT32 tKey )
	{
		const char *lpPtr = (const char*)tKey;
		AEUINT32 uiHash = 0;

		for( int i = 0; lpPtr[i] != 0L; ++i )
			uiHash = 31 * uiHash + lpPtr[i];

		return uiHash & (AEUINT32(-1)>>1); // reserve -1 for empty
	}
};

AECOMPILEERRMSG( AE_BADTYPESIZE );
/// Map strings to integers or pointers.
/// Note that neither the keys nor values are copied so the values
/// must exist for the lifetime of this object.
template <typename V, typename AEAllocator=AEContainerHeapAllocator>
class AEStringMap
{
// Members
	AE_COMPILE_TIME_ASSERT( sizeof(V) <= sizeof(AEUINT32), AE_BADTYPESIZE );

public:
	/// Iterator class.
	/// All iterators are invalidated after a mutating operation. i.e., insertion,removal
	typedef typename AECachedHashMap<AEStringMapOperations, AEAllocator>::AECachedHashMapIterator AEIterator;

protected:
	AECachedHashMap<AEStringMapOperations, AEAllocator> m_mapMap;

// Methods
public:
	AE_DECLARE_NONVIRTUAL_CLASS_ALLOCATOR( TOBEDEFINED, AEStringMap );

	AE_FORCEINLINE AEStringMap( void );

	///	Insert key with associated value val.
	/// If key already exists it is overwritten. The key string is not
	/// copied and must exist for the lifetime of the entry.
	AE_FORCEINLINE void Insert( const char *lpKey, V tVal );

	/// Return the iterator associated with key. Check with isValid().
	AE_FORCEINLINE AEIterator FindKey( const char *lpKey ) const;

	/// If key is present return its iterator, else insert (key,val) and return the new iterator.
	/// Thus the returned iterator is always valid.
	AE_FORCEINLINE AEIterator FindOrInsertKey( const char *lpKey, V tVal );

	/// Return if this map contains the given key.
	AE_FORCEINLINE AEBOOL32 HasKey( const char *lpKey ) const;

	/// Return the value associated with key or if not present, insert and return 'ifNotFound'.
	AE_FORCEINLINE V GetOrInsert( const char *lpKey, V tIfNotFound );

	/// Return the value associated with key or def if not present.
	AE_FORCEINLINE V GetWithDefault( const char *lpKey, V tDefault ) const;

	/// If key present, write value into out and return HK_SUCCESS. Else return HK_FAILURE.
	AE_FORCEINLINE AEUINT32 Get( const char *lpKey, V *lpOut ) const;

	/// Remove pair at "it".
	AE_FORCEINLINE void Remove( AEIterator itIter );

	/// If key present, remove it and return HK_SUCCESS. Otherwise return HK_FAILURE.
	AE_FORCEINLINE AEUINT32 Remove( const char *lpKey );

	/// Return the number of elements in this map.
	AE_FORCEINLINE AEINT32 GetSize( void ) const;

	/// Perform internal consistency check.
	AE_FORCEINLINE AEBOOL32 IsOk( void ) const;

	/// Get an iterator over the keys of this map.
	AE_FORCEINLINE AEIterator GetIterator( void ) const;

	/// Get the key at iterator i.
	/// Do not modify this key directly. If you must change a key, remove and re-add it.
	AE_FORCEINLINE const char *GetKey( AEIterator itIter ) const;

	/// Get the value at iterator i.
	AE_FORCEINLINE V GetValue( AEIterator itIter ) const;

	/// Overwrite the value at iterator i.
	AE_FORCEINLINE void SetValue( AEIterator itIter, V tValue );

	/// Get the next iterator after i.
	AE_FORCEINLINE AEIterator GetNext( AEIterator itIter ) const;

	/// Return if the iterator has reached the end.
	AE_FORCEINLINE AEBOOL32 IsValid( AEIterator itIter ) const;

	/// Remove all keys from the map.
	AE_FORCEINLINE void Clear( void );

	AE_FORCEINLINE void Reset( void );

	/// Swap all data with another map.
	AE_FORCEINLINE void Swap( AEStringMap &refOther );

	/// Insert keys from other into this, overwriting duplicates.
	AE_FORCEINLINE void Merge( const AEStringMap &refOther );

	AE_FORCEINLINE AEINT32 GetCapacity( void ) const;

	AE_FORCEINLINE void Reserve( AEINT32 nNumElements );
};

#include "AEStringMap.inl"

#endif // _AESTRINGMAP_H_

